package com.alibaba.datax.plugin.writer.miniowriter;

import com.alibaba.datax.common.exception.DataXException;
import com.alibaba.datax.common.plugin.RecordReceiver;
import com.alibaba.datax.common.spi.Writer;
import com.alibaba.datax.common.util.Configuration;
import com.alibaba.datax.plugin.writer.miniowriter.handler.WriterHandler;
import com.alibaba.datax.plugin.writer.miniowriter.handler.WriterHandlerSelector;
import com.alibaba.datax.plugin.writer.miniowriter.utils.ExcelUtils;
import com.alibaba.datax.plugin.writer.miniowriter.utils.Minio;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

public class MinioWriter extends Writer {

//    public static final String tempPath = "/bmdata/software/temp/";

    public static final String tempPath = "C:\\Users\\10619\\Desktop\\temp";

    public static class Job extends Writer.Job {
        private static final Logger LOG = LoggerFactory.getLogger(Job.class);

        private Configuration writerSliceConfig;

        private String bucketName;

        private String fileName;

        //时间戳序列
        private String serial;

        private String suffix;

        //清空
        private boolean truncate;

        private Minio minio;

        @Override
        public void init() {
            this.writerSliceConfig = this.getPluginJobConf();
            String endpoint = this.writerSliceConfig.getNecessaryValue(Key.END_POINT, MinioWriterErrorCode.REQUIRED_VALUE);
            String username = this.writerSliceConfig.getNecessaryValue(Key.USERNAME, MinioWriterErrorCode.REQUIRED_VALUE);
            String password = this.writerSliceConfig.getNecessaryValue(Key.PASSWORD, MinioWriterErrorCode.REQUIRED_VALUE);

            this.minio = Minio.builder()
                    .endpoint(endpoint)
                    .accessKey(username)
                    .secretKey(password)
                    .build();
            this.minio.init();
            this.bucketName = this.writerSliceConfig.getString(Key.BUCKET_NAME, "defaultBucket");
            this.fileName = this.writerSliceConfig.getNecessaryValue(Key.FILE_NAME, MinioWriterErrorCode.REQUIRED_VALUE);
            this.serial = this.writerSliceConfig.getString(Key.SERIAL);
            if (StringUtils.isBlank(this.serial)) {
                this.serial = String.valueOf(new Date().getTime());
            }
            this.suffix = this.writerSliceConfig.getNecessaryValue(Key.SUFFIX, MinioWriterErrorCode.REQUIRED_VALUE);
            this.truncate = this.writerSliceConfig.getBool(Key.TRUNCATE, false);
        }

        @Override
        public void prepare() {
            try {
                SupportType.getType(this.suffix);
                this.minio.makeBucket(bucketName);
                if (truncate) {
                    this.minio.removeObjects(bucketName, fileName, item -> item.endsWith(suffix));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void post() {

        }

        @Override
        public void destroy() {
            this.minio = null;
        }

        @Override
        public List<Configuration> split(int mandatoryNumber) {
            Configuration splitTaskConfig = writerSliceConfig.clone();
            String fullFileName = String.format("%s_%s.%s", this.fileName, this.serial, this.suffix);
            try {
                if (this.minio.objectExists(bucketName, fullFileName)) {
                    throw new Exception(String.format("该文件名已存在文件[%s]:[%s]", bucketName, fullFileName));
                }
            } catch (Exception e) {
                throw DataXException.asDataXException(MinioWriterErrorCode.FILE_EXIST, String.format("文件已存在:%s", this.fileName));
            }
            splitTaskConfig.set(Key.FILE_NAME, fullFileName);
            splitTaskConfig.set(Key.SERIAL, this.serial);
            LOG.info(String.format("minio ready write file name:[%s]:[%s]", bucketName, fullFileName));
            return Collections.singletonList(splitTaskConfig);
        }
    }

    public static class Task extends Writer.Task {
        private static final Logger LOG = LoggerFactory.getLogger(Task.class);

        private Configuration writerSliceConfig;

        private String bucketName;

        private String fileName;

        private Minio minio;

        private File tempFile;

        @Override
        public void init() {
            this.writerSliceConfig = this.getPluginJobConf();
            String endpoint = this.writerSliceConfig.getNecessaryValue(Key.END_POINT, MinioWriterErrorCode.REQUIRED_VALUE);
            String username = this.writerSliceConfig.getNecessaryValue(Key.USERNAME, MinioWriterErrorCode.REQUIRED_VALUE);
            String password = this.writerSliceConfig.getNecessaryValue(Key.PASSWORD, MinioWriterErrorCode.REQUIRED_VALUE);

            this.minio = Minio.builder()
                    .endpoint(endpoint)
                    .accessKey(username)
                    .secretKey(password)
                    .build();
            this.minio.init();
            this.bucketName = this.writerSliceConfig.getString(Key.BUCKET_NAME, "defaultBucket");
            this.fileName = this.writerSliceConfig.getNecessaryValue(Key.FILE_NAME, MinioWriterErrorCode.REQUIRED_VALUE);
        }

        @Override
        public void prepare() {
            tempFile = new File(tempPath, fileName);
            if (!tempFile.getParentFile().exists()) {
                boolean mkdirs = tempFile.getParentFile().mkdirs();
                if (!mkdirs) {
                    throw DataXException.asDataXException(MinioWriterErrorCode.FILE_CREATE_ERROR, "临时文件夹创建失败");
                }
            }
        }

        @Override
        public void startWrite(RecordReceiver lineReceiver) {
            try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
                WriterHandler writerHandler = WriterHandlerSelector.buildWriterHandler(this.writerSliceConfig, this.getTaskPluginCollector(), lineReceiver, outputStream);
                writerHandler.startWrite();
            } catch (IOException e) {
                throw DataXException.asDataXException(MinioWriterErrorCode.IO_ERROR, e);
            }

            try (FileInputStream inputStream = new FileInputStream(tempFile)) {
                minio.putObject(this.bucketName, this.fileName, inputStream);
            } catch (Exception e) {
                throw DataXException.asDataXException(MinioWriterErrorCode.MIXED_INDEX_VALUE, e);
            }
        }

        @Override
        public void post() {

        }

        @Override
        public void destroy() {
            this.minio = null;
            boolean delete = tempFile.delete();
            if (!delete) {
                LOG.info("采集完成，但临时文件删除失败");
            }
        }
    }

    public static void main(String[] args) throws IOException {
        List<String> heads = Arrays.asList("名字", "年龄");
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\10619\\Desktop\\test.xlsx");
//        List<List<String>> data = new ArrayList<>();
        List<String> data = Collections.singletonList("1");
//        ExcelUtils.simpleWrite(fileOutputStream, "sdf", heads, data);
        ExcelWriter excelWriter = EasyExcel.write(fileOutputStream).excelType(ExcelTypeEnum.XLSX).build();
        WriteSheet writeSheet = EasyExcel.writerSheet(0, "123")
                .head(Collections.singletonList(heads))
                .registerWriteHandler(ExcelUtils.getSheetStyleStrategy())
                .build();
        excelWriter.write(data, writeSheet);
        excelWriter.finish();
        fileOutputStream.flush();
        fileOutputStream.close();
    }
}
